/**
 * Copyright (C) 2009 - 2013 SC 4ViewSoft SRL
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.codename1.charts.views;

import com.codename1.charts.models.Point;
import com.codename1.charts.models.SeriesSelection;
import com.codename1.ui.geom.Shape;
import com.codename1.util.MathUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * PieChart Segment Selection Management.
 */
public class PieMapper {

    private final List<PieSegment> mPieSegmentList = new ArrayList<PieSegment>();

    private int mPieChartRadius;

    private int mCenterX, mCenterY;

    /**
     * Set PieChart location on screen.
     *
     * @param pieRadius
     * @param centerX
     * @param centerY
     */
    public void setDimensions(int pieRadius, int centerX, int centerY) {
        mPieChartRadius = pieRadius;
        mCenterX = centerX;
        mCenterY = centerY;
    }

    /**
     * If we have all PieChart Config then there is no point in reloading it
     *
     * @param datasetSize
     * @return true if cfg for each segment is present
     */
    public boolean areAllSegmentPresent(int datasetSize) {
        return mPieSegmentList.size() == datasetSize;
    }

    /**
     * Add configuration for a PieChart Segment
     *
     * @param dataIndex
     * @param value
     * @param startAngle
     * @param angle
     */
    public void addPieSegment(int dataIndex, float value, float startAngle, float angle) {
        mPieSegmentList.add(new PieSegment(dataIndex, value, startAngle, angle));
    }

    /**
     * Clears the pie segments list.
     */
    public void clearPieSegments() {
        mPieSegmentList.clear();
    }

    /**
     * Fetches angle relative to pie chart center point where 3 O'Clock is 0 and
     * 12 O'Clock is 270degrees
     *
     * @param screenPoint
     * @return angle in degress from 0-360.
     */
    public double getAngle(Point screenPoint) {
        double dx = screenPoint.getX() - mCenterX;
        // Minus to correct for coord re-mapping
        double dy = -(screenPoint.getY() - mCenterY);

        double inRads = com.codename1.util.MathUtil.atan2(dy, dx);

        // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12
        // O'clock
        if (inRads < 0)
            inRads = Math.abs(inRads);
        else
            inRads = 2 * Math.PI - inRads;

        return Math.toDegrees(inRads);
    }

    /**
     * Checks if Point falls within PieChart
     *
     * @param screenPoint
     * @return true if in PieChart
     */
    public boolean isOnPieChart(Point screenPoint) {
        // Using a bit of Pythagoras
        // inside circle if (x-center_x)**2 + (y-center_y)**2 <= radius**2:

        double sqValue = (MathUtil.pow(mCenterX - screenPoint.getX(), 2) + MathUtil.pow(
                mCenterY - screenPoint.getY(), 2));

        double radiusSquared = mPieChartRadius * mPieChartRadius;
        boolean isOnPieChart = sqValue <= radiusSquared;
        return isOnPieChart;
    }

    /**
     * Fetches the SeriesSelection for the PieSegment selected.
     *
     * @param screenPoint - the user tap location
     * @return null if screen point is not in PieChart or its config if it is
     */
    public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
        if (isOnPieChart(screenPoint)) {
            double angleFromPieCenter = getAngle(screenPoint);

            for (PieSegment pieSeg : mPieSegmentList) {
                if (pieSeg.isInSegment(angleFromPieCenter)) {
                    return new SeriesSelection(0, pieSeg.getDataIndex(), pieSeg.getValue(),
                            pieSeg.getValue());
                }
            }
        }
        return null;
    }

    private Shape getSegmentShape(PieSegment segment) {
        return segment.getShape(mCenterX, mCenterY, mPieChartRadius);
    }

    private PieSegment getSegment(int dataIndex) {
        for (PieSegment s : mPieSegmentList) {
            if (dataIndex == s.getDataIndex()) {
                return s;
            }
        }
        return null;
    }

    public Shape getSegmentShape(int dataIndex) {
        PieSegment seg = getSegment(dataIndex);
        if (seg != null) {
            return getSegmentShape(seg);
        }
        return null;
    }


}
